package rest

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/samber/lo"
	"github.com/sirupsen/logrus"
	"gopkg.in/guregu/null.v4"
	"monoblog/common"
	"monoblog/domain/auth"
	"monoblog/domain/dto"
	"monoblog/domain/model"
	"monoblog/domain/service"
	"monoblog/util"
)

/*
前端综合接口
*/

// SendSmsCode 发送验证码
func SendSmsCode(ctx *gin.Context) {
	tag, _ := ctx.GetQuery("tag")
	phone, _ := ctx.GetQuery("phone")
	if phone == "" {
		common.Fail(ctx, "参数校验失败", errors.New("phone参数不能为空"))
		return
	}

	logrus.Infof("[aid: %s] 发送验证码 tag=%s, phone=%s", ctx.Value("aid"), tag, phone)
	smsCode := auth.SmsCodeCreateAndSend(ctx, phone)

	//此次是模拟发送到手机（真实场景不能直接返回smsCode）
	common.Success(ctx, smsCode)
}

// CheckOccupied 检查username或phone或email是否已被占用
func CheckOccupied(ctx *gin.Context) {
	username, _ := ctx.GetQuery("username")
	phone, _ := ctx.GetQuery("phone")
	email, _ := ctx.GetQuery("email")

	//先校验参数是否为空
	if username == "" && phone == "" && email == "" {
		common.Fail(ctx, "username、phone、email 参数不能为空", nil)
		return
	}

	if username != "" {
		if b, _ := service.GetUserService().ExistsByUserId(ctx, username); b {
			common.Success(ctx, true)
			return
		}
	} else if phone != "" {
		if b, _ := service.GetUserService().ExistsByPhoneOrEmail(ctx, phone); b {
			common.Success(ctx, true)
			return
		}
	} else if email != "" {
		if b, _ := service.GetUserService().ExistsByPhoneOrEmail(ctx, email); b {
			common.Success(ctx, true)
			return
		}
	}

	common.Success(ctx, false)
}

// AuthLogin 用户登录
func AuthLogin(ctx *gin.Context) {
	var form dto.LoginForm
	if err := ctx.ShouldBind(&form); err != nil {
		common.Fail(ctx, "Body数据绑定失败", err)
		return
	}
	//初始化校验器并执行字段校验
	validate := validator.New()
	if err := validate.Struct(form); err != nil {
		common.Fail(ctx, "参数校验失败", err)
		return
	}
	//查询user信息
	user, err := service.GetUserService().FindByUserId(ctx, form.Username)
	if err != nil || !util.PasswordVerify(user.Password, form.Password) {
		common.Fail(ctx, "账号或密码错误", err)
		return
	}

	//生成jwt token
	loginUser := &auth.LoginUser{
		UID:    user.Username,
		Name:   user.Nickname,
		Avatar: user.AvatarUrl,
		Roles:  user.Roles,
	}

	accessToken, err := auth.GenerateJWT(loginUser, common.GetSecretKeyProperties().AccessSecretKey)
	if err != nil {
		common.Fail(ctx, "Access Token 生成失败", err)
		return
	}

	//set cookie 24小时
	ctx.SetCookie("token", accessToken, 24*60*60, "/", "", false, true)

	common.Success(ctx, map[string]string{"token": accessToken})
}

// AuthLogout 用户退出登录
func AuthLogout(ctx *gin.Context) {
	//获取登录用户
	if _, ok := ctx.Get("user"); !ok {
		common.Fail(ctx, "用户未登录", nil)
	}

	// 清除认证相关cookie
	ctx.SetCookie("token", "", -1, "/", "", false, true)
	ctx.SetCookie("sessionid", "", -1, "/", "", false, true)

	common.Success(ctx, nil)
}

// CheckIsLogged 检查用户是否已登录
func CheckIsLogged(ctx *gin.Context) {
	//获取登录用户
	_, ok := ctx.Get("user")
	common.Success(ctx, ok)
}

// PopularBlogs 首页文章列表
func PopularBlogs(ctx *gin.Context) {
	//首页文章列表
	articles, err := service.GetArticleService().PopularBlogs(ctx, common.BaseQuery{Page: 1, Size: 20})
	if err != nil {
		common.Fail(ctx, "查询首页文章列表失败", err)
		return
	}

	common.Success(ctx, articles)
}

// StatsAtBlog 博客状态数据：是否点赞、收藏
func StatsAtBlog(ctx *gin.Context) {
	blogId := ctx.Query("target")
	var userId string // 用户ID

	if blogId == "" {
		common.Fail(ctx, "参数错误", errors.New("target is required"))
		return
	}

	if user, ok := ctx.Get("user"); ok {
		userId = user.(*auth.LoginUser).UID
	}
	if userId == "" {
		common.Fail(ctx, "用户未登录", errors.New("user not login"))
		return
	}

	// 是否已点赞、已收藏
	collectsMap, err := service.GetInterestService().StatsAtBlog(ctx, blogId, userId)
	if err != nil {
		common.Fail(ctx, "查询失败", err)
		return
	}
	common.Success(ctx, collectsMap)
}

// StatsAtUser 用户状态数据：是否关注、已拉黑
func StatsAtUser(ctx *gin.Context) {
	targetId := ctx.Query("target")
	var userId string // 用户ID

	if targetId == "" {
		common.Fail(ctx, "参数错误", errors.New("target is required"))
		return
	}

	if user, ok := ctx.Get("user"); ok {
		userId = user.(*auth.LoginUser).UID
	}
	if userId == "" {
		common.Fail(ctx, "用户未登录", errors.New("user not login"))
		return
	}

	//是否已关注、已拉黑
	collectsMap, err := service.GetInterestService().StatsAtUser(ctx, targetId, userId)
	if err != nil {
		common.Fail(ctx, "查询失败", err)
		return
	}
	common.Success(ctx, collectsMap)
}

// SettingsByUser 用户的设置
func SettingsByUser(ctx *gin.Context) {
	var userId string // 用户ID

	if user, ok := ctx.Get("user"); ok {
		userId = user.(*auth.LoginUser).UID
	} else {
		common.Fail(ctx, "用户未登录", errors.New("user not login"))
		return
	}

	common.Success(ctx, map[string]string{"userId": userId})
}

// MomentsByUser 用户动态列表
func MomentsByUser(ctx *gin.Context) {
	userId := ctx.Query("userId") //用户ID
	if userId == "" {
		common.Fail(ctx, "参数错误", errors.New("userId is required"))
		return
	}

	//查询用户动态列表
	moments, err := service.GetMomentService().FindListByUserId(ctx, userId)
	if err != nil {
		logrus.Errorf("[aid: %s] 查询用户动态列表失败, userId: %s, err: %v", ctx.Value("aid"), userId, err)
		common.Fail(ctx, "查询用户动态列表失败", err)
		return
	}

	common.Success(ctx, moments)
}

// SectionsByUser 用户专栏列表
func SectionsByUser(ctx *gin.Context) {
	userId := ctx.Query("userId") //用户ID
	if userId == "" {
		userId = ctx.GetString("userId")
	}
	if userId == "" {
		common.Fail(ctx, "参数错误", errors.New("userId is required"))
		return
	}

	sections, err := service.GetSectionService().SectionsByUserId(ctx, userId)
	if err != nil {
		common.Fail(ctx, "查询用户专栏列表失败", err)
		return
	}
	common.Success(ctx, sections)
}

// FavoritesByUser 用户收藏列表（收藏的文章）
func FavoritesByUser(ctx *gin.Context) {
	userId := ctx.Query("userId") //用户ID
	if userId == "" {
		common.Fail(ctx, "参数错误", errors.New("userId is required"))
		return
	}

	blogIds, err := service.GetInterestService().GetFavorites(ctx, userId)
	if err != nil {
		common.Fail(ctx, "查询用户收藏列表失败", err)
		return
	}
	favorites, err := service.GetArticleService().FindInBlogIds(ctx, blogIds)
	if err != nil {
		common.Fail(ctx, "查询用户收藏列表失败", err)
		return
	}

	common.Success(ctx, favorites)
}

// FollowsByUser 用户关注列表（关注的用户）
func FollowsByUser(ctx *gin.Context) {
	userId := ctx.Query("userId") //用户ID
	if userId == "" {
		common.Fail(ctx, "参数错误", errors.New("userId is required"))
		return
	}

	interest, err := service.GetInterestService().GetInterest(ctx, userId)
	if err != nil {
		common.Fail(ctx, "查询用户关注列表失败", err)
		return
	}

	follows, err := service.GetUserService().FindInUserIds(ctx, interest.FollowIds)
	if err != nil {
		common.Fail(ctx, "查询用户关注列表失败", err)
		return
	}

	followsDto := lo.Map(follows, func(item *model.WebUser, index int) *dto.UserResp {
		userResp := dto.ConvertWebUserToUserResp(item, index)
		userResp.IsFollow = null.BoolFrom(true)
		return userResp
	})
	common.Success(ctx, followsDto)
}

// SubmitFeedback 提交反馈
func SubmitFeedback(ctx *gin.Context) {
	var form dto.FeedbackReqForm
	if err := ctx.ShouldBind(&form); err != nil {
		common.Fail(ctx, "Body数据绑定失败", err)
		return
	}
	//初始化校验器并执行字段校验
	validate := validator.New()
	if err := validate.Struct(form); err != nil {
		common.Fail(ctx, "参数校验失败", err)
		return
	}

	// 登录用户信息
	if user, ok := ctx.Get("user"); ok {
		form.LoginUser = user.(*auth.LoginUser)
	}

	err := service.GetFeedbackService().Add(ctx, form)
	if err != nil {
		common.Fail(ctx, "提交反馈失败", err)
		return
	}
	common.Success(ctx, nil)
}

// GetFeedbacksByUser 查看用户的历史反馈列表
func GetFeedbacksByUser(ctx *gin.Context) {
	var userId string // 用户ID
	if user, ok := ctx.Get("user"); ok {
		userId = user.(*auth.LoginUser).UID
	}
	if userId == "" {
		common.Fail(ctx, "用户未登录", errors.New("user not login"))
		return
	}

	feedbacks, err := service.GetFeedbackService().FindListByUserId(ctx, userId)
	if err != nil {
		logrus.Errorf("[aid: %s] 查询用户历史反馈列表失败, userId: %s, err: %v", ctx.Value("aid"), userId, err.Error())
		common.Fail(ctx, "查询用户历史反馈列表失败", err)
		return
	}
	common.Success(ctx, feedbacks)
}

// NotificationsByUser 通知列表
func NotificationsByUser(ctx *gin.Context) {
	userId := ctx.Query("userId") //用户ID
	if userId == "" {
		common.Fail(ctx, "参数错误", errors.New("userId is required"))
		return
	}

	//notifications, err := service.GetNotificationService().FindListByUserId(ctx, userId)
	//if err != nil {
	//	logrus.Errorf("[aid: %s] 查询用户的通知列表失败, userId: %s, err: %v", ctx.Value("aid"), userId, err)
	//	common.Fail(ctx, "查询用户的通知列表失败", err)
	//	return
	//}

	common.Success(ctx, []*model.Notification{})
}
